#ifndef NUMBER_VECTOR_H
#define NUMBER_VECTOR_H

#include <iostream>
#include <initializer_list>
#include <iterator>
#include <cstddef>

template <typename T>
class NumberVector {
public:
    class iterator {
    private:
        NumberVector &container;
        int ind;
    private:
        using iterator_category = std::random_access_iterator_tag;
        using difference_type = std::ptrdiff_t;
        using value_type = T;
        using pointer = T*;
        using reference = T&;

        friend class NumberVector;
        iterator(NumberVector &num_vec, int ind);
    public:
        iterator(const iterator &other);
    public:
        iterator & operator=(const iterator &other);

        reference operator*() const;
        pointer operator->();

        iterator & operator++();
        iterator operator++(int);
        iterator & operator--();
        iterator operator--(int);

        iterator operator+(int a);
        template <typename U>
        friend iterator operator+(int a, iterator &it);
        iterator operator-(int a);
        difference_type operator-(const iterator &other);
        iterator& operator+=(int a);
        iterator& operator-=(int a);
        reference operator[](int ind);

        bool operator==(const iterator &other);
        bool operator!=(const iterator &other);
        bool operator<(const iterator &other);
        bool operator>(const iterator &other);
        bool operator<=(const iterator &other);
        bool operator>=(const iterator &other);
    };
private:
    T *nums;
    int _size;
    // int capacity;
public:
    // Constructors & destructor
    NumberVector();
    NumberVector(int n);
    NumberVector(int n, T a);
    NumberVector(std::initializer_list<T> init);
    NumberVector(const NumberVector &other);
    ~NumberVector();

    // Overloads
    NumberVector & operator=(const NumberVector &other);
    NumberVector & operator=(NumberVector &&other) noexcept;
    T & operator[](int ind);
    operator int(); // return size of number vector
    NumberVector operator*(T mult);
    NumberVector operator+(T num);

    // Friends functions
    template <typename U>
    friend std::ostream & operator<<(std::ostream &os, const NumberVector<U> &num_vec);
    template <typename U>
    friend std::istream & operator>>(std::istream &is, NumberVector<U> &num_vec);
    template <typename U>
    friend iterator operator+(int a, iterator &it);

    // Public methods (interface)
    int size() const;
    NumberVector::iterator begin();
    NumberVector::iterator end();
};

#include "number_vector.hpp"

#endif // NUMBER_VECTOR_H
